package com.epoint.nio.socket2.write;

import com.epoint.nio.NioUtil;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

public class Server {
    public static void main(String[] args) throws Exception {
        try(
            // 2.创建服务器
            ServerSocketChannel server = ServerSocketChannel.open()
        ){
            // 2.1绑定监听端口
            server.bind(new InetSocketAddress(8080));
            // 2.2设置非阻塞
            server.configureBlocking(false);

            // 创建Select
            Selector selector = Selector.open();
            server.register(selector, SelectionKey.OP_ACCEPT);

            /**
             * 4.一直循环接受客户端
             *
             */
            while (true){
                selector.select();

                // 获取所有事件
                Set<SelectionKey> selectionKeys = selector.selectedKeys();

                // 因为下面会涉及到循环里进行操作，故这里直接获取迭代器
                Iterator<SelectionKey> iterator = selectionKeys.iterator();

                while (iterator.hasNext()){
                    // 事件
                    SelectionKey key = iterator.next();

                    // 根据事件类型进行判断
                    if(key.isAcceptable()){
                        // 获取对应的通道
                        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                        // 客户端
                        SocketChannel accept = channel.accept();
                        if(accept != null){
                            System.out.println("有一个客户端连接" + accept);
                            // 设置非阻塞
                            accept.configureBlocking(false);

                            // 为该客户端绑定读事件
//                            accept.register(selector, SelectionKey.OP_READ);

                            // 模拟传输一个很大的文件
                            StringBuilder sb = new StringBuilder();
                            for (int i = 0; i < 20000000; i++) {
                                sb.append("j");
                            }

                            // 1.开辟一个缓存buffer
                            ByteBuffer buffer = Charset.defaultCharset().encode(sb.toString());

                            /**
                             * 观察一个现象：
                             *  我们循环打印write结果的时候，发现他经常是空数据，这就表现出，很多时候是取不到数据的，
                             *  相当于程序空跑，浪费性能，所以如果能也有一个 检测 机制 就好了，也就是当真正有数据得时候，
                             *  我们才进来write，美滋滋。这样进一步提高了系统的性能。虽然不能达到多线程那种效果。
                             */
                            while(buffer.hasRemaining()){
                                int write = accept.write(buffer);
                                System.out.println(write);
                            }
                        }
                    }
                    iterator.remove();
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
